package de.tud.stg.emergent.policy.utils;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.StringTokenizer;


import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMXMLBuilderFactory;
import org.apache.axiom.om.OMXMLParserWrapper;
import org.apache.axiom.om.util.AXIOMUtil;

import org.apache.axis2.util.PolicyUtil;
import org.apache.neethi.All;
import org.apache.neethi.ExactlyOne;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyBuilder;
import org.apache.neethi.PolicyComponent;
import org.apache.neethi.PolicyEngine;
import org.apache.neethi.PolicyOperator;


public class CommonPolicyUtils {

	public static final String policy_Prefix_Path = ".\\resources\\policy\\";
	
	public static final String policy_True_Path  = policy_Prefix_Path + "alwaysTruePolicy.xml";
	public static final String policy_False_Path = policy_Prefix_Path + "alwaysFalsePolicy.xml";
	public static final String policy_And_Path   = policy_Prefix_Path + "andPolicy.xml";
	public static final String policy_Empty_Path = policy_Prefix_Path + "emptyPolicy.xml";
	
	public static final String rampartRepositoryPath = ".\\resources\\axis-dir\\rampart";

	private static Policy getNeethiPolicyFromFileError(String fileName) {
		PolicyBuilder policyEngine = new PolicyBuilder();
		InputStream input = null;
		try {
			input = new FileInputStream(fileName);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		XMLStreamReader reader = null;
		try {
			reader = XMLInputFactory.newInstance().createXMLStreamReader(input);
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FactoryConfigurationError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return policyEngine.getPolicy(reader);
	}

	

//	public static org.xmlsoap.schemas.ws._2004._09.policy.Policy convertNeethiToADBPolicy(Policy neethiPolicy) {
//       	
//      
//		   OMElement policyComponentAsOMElement = null;
//			try {
//				policyComponentAsOMElement = PolicyUtil.getPolicyComponentAsOMElement(neethiPolicy);
//			} catch (XMLStreamException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			} catch (FactoryConfigurationError e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			
//			org.xmlsoap.schemas.ws._2004._09.policy.Policy.Factory factoryADBPolicyFromOM = new org.xmlsoap.schemas.ws._2004._09.policy.Policy.Factory();
//			
//			XMLStreamReader normalizedOMPolicyReader = policyComponentAsOMElement.getXMLStreamReader();
//			
//			org.xmlsoap.schemas.ws._2004._09.policy.Policy parsedPolicy = null;
//			try {
//				parsedPolicy = factoryPolicyFromOM.parse(normalizedOMPolicyReader);
//			} catch (Exception e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//            
//			
//			return parsedPolicy;
//		}
	
	
	
	
	

	public static Policy getNeethiPolicyFromFile(String fileName) {
//		PolicyBuilder policyEngine = new PolicyBuilder();
//		InputStream input = new FileInputStream(fileName);
//		XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(input);
//		return policyEngine.getPolicy(reader);
		
		//String filePath = new File(testResourceDir, name).getAbsolutePath();
		OMXMLParserWrapper builder = null;
		try {
			builder = OMXMLBuilderFactory.createOMBuilder(new FileInputStream(fileName));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		OMElement axiomElement = builder.getDocumentElement();
		
		return getNeethiFromAxiomPolicy(axiomElement);
	}



	public static OMElement convertNeethiToOMElement(Policy neethiPolicy) {
		OMElement policyComponentAsOMElement = null;
			try {
				policyComponentAsOMElement = PolicyUtil.getPolicyComponentAsOMElement(neethiPolicy);
			} catch (XMLStreamException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (FactoryConfigurationError e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		return policyComponentAsOMElement;
	}

	public static Policy getNeethiFromAxiomPolicy(OMElement axiomPolicy) {
		return PolicyEngine.getPolicy(axiomPolicy);
	}
	public static Policy getNeethiFromStringPolicy(String stringPolicy) {
		OMElement axiomFromString = getAxiomFromString(stringPolicy);
		
		return getNeethiFromAxiomPolicy(axiomFromString);
	}
	
	public static OMElement getAxiomFromString(String str){
		OMElement elt = null;
		try {
			elt = AXIOMUtil.stringToOM(str);
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return elt;

	}
	
	public static String getStringFromAxiom(OMElement axiomElt){
		
		
		try {
			return axiomElt.toStringWithConsume();
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public static void showPolicy(Policy policy) {
		XMLStreamWriter writer = null;
		try {
			writer = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
			policy.serialize(writer);
			writer.flush();
			writer.close();
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FactoryConfigurationError e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	final String indentation = "  ";
	String currentIndentation = "";
	int indentCnt = 0;
	Policy generatedPolicy;	
		
	/**
	 * Returns the current indentation.
	 * @return
	 */
	public String indent() { return /*indentCnt+*/currentIndentation; }
	
	/**
	 * Indents a given string with no indentation with the current indentation (adds indentation in front of every line).
	 * @param toIndent
	 * @return Return the indented string
	 */
	public String indent(String toIndent) {
		String result = "";
		StringTokenizer st = new StringTokenizer(toIndent,"\n");
		while (st.hasMoreTokens()) {
			String line = st.nextToken();
			result += indent() + line + lineBreak();
		} 
		return result;
    }
	
	/**
	 * Return a line break. 
	 * @return
	 */
	public String lineBreak() { return "\n"; }
	
	/**
	 * Increases the current indentation, but returns its last value.
	 * @return Value of current indentation, before is has been increased.
	 */
	public String incIndent() { 
		String oldIndentation = indent(); 
		currentIndentation += indentation; 
		indentCnt++;
		return oldIndentation; 
	}
	
	/**
	 * Decreases the current indentation, but returns its last value.
	 * @return Value of current indentation, before is has been decreased.
	 */
	public String decIndent() { 
		currentIndentation = currentIndentation.substring(0,currentIndentation.length()-indentation.length());
		indentCnt--;
		return indent(); 
	}
	/*
public enum SecurityLevel { 
  high, medium, low
}
	public Object eval(HashMap map, Closure cl) {
		cl.delegate = this;
		cl.resolveStrategy = Closure.DELEGATE_FIRST;
		cl.call();
	}

	public SecurityLevel high = SecurityLevel.high;
	public SecurityLevel low = SecurityLevel.low;
	public SecurityLevel medium = SecurityLevel.medium;
	
	@PopartType(clazz=PopartStructuredElementKeyword.class,breakpointPossible=0)
	public String if_p0_then_p1_else_p2(String condition, Closure ifClause, Closure elseClause) {
		String result = incIndent() + """<emergent:If condition="$condition">""" + lineBreak(); 
		 
		result += incIndent() + '<emergent:IfClause>' + lineBreak();
		result += ifClause.call();
		result += decIndent() + '</emergent:IfClause>' + lineBreak();
		  
		result += incIndent() + '<emergent:ElseClause>'+ lineBreak(); 
        result += elseClause.call(); 
		result += decIndent() + '</emergent:ElseClause>' + lineBreak();
		  
		result += decIndent() + '</emergent:If>' + lineBreak();
		
		return result; 
	}
	*/
	public String getEmptyPolicy() {
		return indent() + "<sp:Policy/>" + lineBreak();
	}
	
	public void  always_true() {
		PolicyOperator exactlyOne = new ExactlyOne();
		PolicyOperator all =  new All(exactlyOne);
		generatedPolicy.addPolicyComponent(exactlyOne);

	}
	
	public void always_false() {
		PolicyOperator exactlyOne = new ExactlyOne();
		generatedPolicy.addPolicyComponent(exactlyOne);
	}
	
	public void and(PolicyComponent component1, PolicyComponent component2) {
		
			PolicyOperator exactlyOne = new ExactlyOne();
			PolicyOperator all =  new All(exactlyOne);
			all.addPolicyComponent(component1);
			all.addPolicyComponent(component2);
			generatedPolicy.addPolicyComponent(exactlyOne);
			
		}
	public String and(String alternative) {
		String result = "";
		result += incIndent() + "<sp:All>" + lineBreak();
		result += alternative;
		result += decIndent()+ "</sp:All>" + lineBreak();
		return result;
	}
	
	public String xor(String alternative) {
		String result = "";
		result += incIndent() + "<sp:ExactlyOnce>" + lineBreak();
		result += alternative;
		result += decIndent()+ "</sp:ExactlyOnce>" + lineBreak();
		return result;
	}
	
	public void xor(PolicyComponent component1, PolicyComponent component2) {

		PolicyOperator exactlyOne = new ExactlyOne();
		exactlyOne.addPolicyComponent(component1);
		exactlyOne.addPolicyComponent(component2);
		generatedPolicy.addPolicyComponent(exactlyOne);
	}
	
	public void prologue() {
		generatedPolicy = new Policy();
	}
	
	public Policy epilogue() throws XMLStreamException{
//		def xw = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
//		generatedPolicy.serialize(xw);
//		xw.flush();
//	    xw.close();
		return generatedPolicy;
		
	}




	
	
}
